﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using Tesla.Core;

namespace Tesla.Graphics.Implementation {

    /// <summary>
    /// Abstract class for concrete subclasses to provide the underlying implementation of <see cref="IndexBuffer"/>.
    /// </summary>
    public abstract class IndexBufferImplementation : GraphicsResourceImplementation {
        private int _indexCount;
        private IndexFormat _format;
        private ResourceUsage _bufferUsage;

        /// <summary>
        /// Get the number of indices in the buffer.
        /// </summary>
        public int IndexCount {
            get {
                return _indexCount;
            }
        }

        /// <summary>
        /// Get the index format, 32 (int) or 16 (short) bits.
        /// </summary>
        public IndexFormat IndexFormat {
            get {
                return _format;
            }
        }

        /// <summary>
        /// Get the buffer usage, either static or dynamic.
        /// </summary>
        public ResourceUsage BufferUsage {
            get {
                return _bufferUsage;
            }
        }

        /// <summary>
        /// Creates a new instance of <see cref="IndexBufferImplementation"/>.
        /// </summary>
        /// <param name="indexFormat">The index format.</param>
        /// <param name="indexCount">The number of indices the buffer will contain.</param>
        /// <param name="usage">The resource usage specifying the type of memory the buffer should use.</param>
        protected IndexBufferImplementation(IndexFormat indexFormat, int indexCount, ResourceUsage usage) {
            _format = indexFormat;
            _indexCount = indexCount;
            _bufferUsage = usage;
        }

        /// <summary>
        /// Creates a new instance of <see cref="IndexBufferImplementation"/>.
        /// </summary>
        /// <param name="indices">The index data.</param>
        /// <param name="usage">The resource usage specifying the type of memory the buffer should use.</param>
        /// <exception cref="System.ArgumentNullException">Thrown if the index data is null.</exception>
        protected IndexBufferImplementation(DataBuffer<int> indices, ResourceUsage usage) {
            if(indices == null) {
                throw new ArgumentNullException("indices", "Indices cannot be null.");
            }
            _format = IndexFormat.ThirtyTwoBits;
            _indexCount = indices.Length;
            _bufferUsage = usage;
        }

        /// <summary>
        /// Creates a new instance of <see cref="IndexBufferImplementation"/>.
        /// </summary>
        /// <param name="indices">The index data.</param>
        /// <param name="usage">The resource usage specifying the type of memory the buffer should use.</param>
        /// <exception cref="System.ArgumentNullException">Thrown if the index data is null.</exception>
        protected IndexBufferImplementation(DataBuffer<short> indices, ResourceUsage usage) {
            if(indices == null) {
                throw new ArgumentNullException("indices", "Indices cannot be null.");
            }
            _format = IndexFormat.SixteenBits;
            _indexCount = indices.Length;
            _bufferUsage = usage;
        }

        /// <summary>
        /// Writes data from the array to the index buffer.
        /// </summary>
        /// <typeparam name="T">The type of data in the index buffer - int or short.</typeparam>
        /// <param name="data">Array to copy the data from</param>
        /// <param name="startIndex">Starting index in the array at which to start copying from</param>
        /// <param name="elementCount">Number of indices to write</param>
        /// <param name="offsetInBytes">Offset from the start of the index buffer at which to start writing at</param>
        /// <param name="writeOptions">Write options, used only if this is a dynamic buffer. None, discard, no overwrite</param>
        /// <remarks>See implementors for exceptions that may occur.</remarks>
        public abstract void SetData<T>(T[] data, int startIndex, int elementCount, int offsetInBytes, DataWriteOptions writeOptions) where T : struct;

        /// <summary>
        /// Reads data from the index buffer into the array.
        /// </summary>
        /// <typeparam name="T">The type of data in the index buffer - int or short.</typeparam>
        /// <param name="data">Array to write the data to</param>
        /// <param name="startIndex">Starting index in the array at which to start writing to</param>
        /// <param name="elementCount">Number of indices to read</param>
        /// <param name="offsetInBytes">Offset from the start of the index buffer at which to start copying from</param>
        /// <remarks>See implementors for exceptions that may occur.</remarks>
        public abstract void GetData<T>(T[] data, int startIndex, int elementCount, int offsetInBytes) where T : struct;
    }
}
